/******************************************
 * Memory manager
 ******************************************/

#include "memory.h"
#include "messages.h"
#include "prism.h"

#include <stdlib.h>
#include <string.h>


void * Variables[SIZE];
struct Image * List = NULL;


void * allocateVariable( enum Variable variable, int size, enum FillType fill)
{
    DEBUG1( "Entering..." );

    void * ptr = NULL;

    if (!Variables[variable]) {
        ptr = malloc( size );

        if (!ptr) {
            ERROR1( "Memory allocation error" );
        }

        Variables[variable] = ptr;

        DEBUG1( "Memory allocation was successful" );
    }

    if (fill == FILL) {
        memset( Variables[variable], 0, size );

        DEBUG1( "Memory filled with zeros" );
    }

    DEBUG1( "Variable is ready to use" );
    DEBUG1( "Leaving..." );
    return Variables[variable];
}


void * allocateMemory( int size )
{
    DEBUG1( "Entering..." );

    void * ptr = NULL;

    ptr = malloc( size );
    if (!ptr) {
        ERROR1( "Memory allocation error" );
    }

    DEBUG1( "Memory allocation was successful" );
    DEBUG1( "Leaving..." );
    return ptr;
}

void * allocatePictureMemory( int size, enum FillType fill, enum ErrorBehaviour err )
{
    DEBUG1( "Entering..." );

    struct Image * newElement;
    static int indexCounter = 0;

    size += sizeof( struct Image );
    newElement = malloc( size );
    if (!newElement) {
        if (err == EXIT_ON_ERROR) {
            ERROR1( "Memory allocation error" );
        }

        DEBUG1( "Out of memory" );
        return NULL;
    }

    newElement->Index = indexCounter;
    newElement->Pointer = newElement + sizeof( struct Image );
    indexCounter++;

    if (!List) {
        List = newElement;
        List->Next = NULL;
        List->Prev = NULL;

    } else {
        newElement->Next = List;
        newElement->Prev = NULL;
        List->Prev = newElement;
        List = newElement;
    }

    if (fill == FILL) {
        memset( List->Pointer, 0, size );
    }

    DEBUG1( "Memory allocation was successful" );
    DEBUG1( "Leaving..." );
    return List->Pointer;
}

void freePictureMemory( int index )
{
    DEBUG1( "Entering..." );

    struct Image * current = List;

    while (current) {
        if (current->Index == index) {
            // TODO: Némi csekkolás, hogy melyik létezik és melyik nem
            if (current->Next) {
                current->Next->Prev = current->Prev;
            }
            
            if (current->Prev)
                current->Prev->Next = current->Next;

            free( current );

            DEBUG1( "Memory released successfully" );
            return;
        }
        current = current->Next;
    }

    WARNING1( "Invalid index was given for freeing up" );
    DEBUG1( "Memory couldn't release" );
    DEBUG1( "Leaving..." );
    return;
}


void freeMemory( void * ptr )
{
    DEBUG1( "Entering..." );

    free( ptr );

    DEBUG1( "Memory released :)" );
    DEBUG1( "Leaving..." );
    return;
}


void freeAll()
{
    DEBUG1( "Entering..." );

    struct Image * current;
    int i;

    while (List) {
        current = List;
        List = List->Next;
        free( current );
    }

    DEBUG1( "List is clean :)" );

    for (i=0; i<SIZE; i++ ) {
        free( Variables[i] );
    }

    DEBUG1( "Variables released :)" );
    DEBUG1( "Leaving..." );
    return;
}

void initMemoryManager( void )
{
    DEBUG1( "Entering..." );

    for( int i=0; i<SIZE; i++ ) {
        Variables[i] = NULL;
    }

    DEBUG1( "Variable array initialized" );
    DEBUG1( "Leaving..." );
    return;
}
